
//
// Copyright (c) 2008, the /*jupiter jazz*/ group
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the /*jupiter jazz*/ group nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY the /*jupiter jazz*/ group ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL the /*jupiter jazz*/ group BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#ifndef CLASSLIB_STLEXT_H
#define CLASSLIB_STLEXT_H

// Standard headers.
#include <algorithm>
#include <cassert>
#include <cstddef>

namespace foundation
{

//
// Utility functions.
//

// Return the successor or predecessor of a given iterator.
template <typename Iterator> Iterator succ(Iterator i);
template <typename Iterator> Iterator pred(Iterator i);

// Clear a container and release the memory.
template <typename T>
void clear_release_memory(T& container);

// Clear a container but keep memory allocated.
template <typename T>
void clear_keep_memory(T& container);


//
// Helper classes to iterate over the elements of a collection.
//
// Example:
//
//   vector<int> v;
//   ...
//   for (const_each<vector<int> > i = v; i; ++i)
//       cerr << *i << endl;
//

template <typename C>
class const_each
{
  public:
    // Types.
    typedef typename C::const_iterator const_iterator;
    typedef typename const_iterator::value_type value_type;

    // Constructor.
    const_each(const C& c);

    // Conversion to bool, return true if the iterator
    // hasn't yet reached the end of the collection.
    operator bool() const;

    // Preincrement operator.
    void operator++();

    // Iterator comparison.
    bool operator<(const const_iterator& rhs) const;
    bool operator>(const const_iterator& rhs) const;

    // Iterator dereference.
    const value_type& operator*() const;
    const value_type* operator->() const;

  private:
    const_iterator i, e;
};

template <typename C>
class each
{
  public:
    // Types.
    typedef typename C::iterator iterator;
    typedef typename iterator::value_type value_type;

    // Constructor.
    each(C& c);

    // Conversion to bool, return true if the iterator
    // hasn't yet reached the end of the collection.
    operator bool() const;

    // Preincrement operator.
    void operator++();

    // Iterator comparison.
    bool operator<(const iterator& rhs) const;
    bool operator>(const iterator& rhs) const;

    // Iterator dereference.
    value_type& operator*();
    value_type* operator->();

  private:
    iterator i, e;
};


//
// Utility functions implementation.
//

// Return the successor or predecessor of a given iterator.
template <typename Iterator>
inline Iterator succ(Iterator i)
{
    return ++i;
}
template <typename Iterator>
inline Iterator pred(Iterator i)
{
    return --i;
}

// Clear a container and release the memory.
template <typename T>
inline void clear_release_memory(T& container)
{
    T empty;
    std::swap(empty, container);
    assert(container.empty());
    assert(container.capacity() == 0);
}

// Clear a container but keep memory allocated.
template <typename T>
inline void clear_keep_memory(T& container)
{
#ifndef NDEBUG
    const size_t old_capacity = container.capacity();
#endif
    container.erase(container.begin(), container.end());
    assert(container.capacity() == old_capacity);
}


//
// const_each class implementation.
//

// Constructor.
template <typename C>
inline const_each<C>::const_each(const C& c)
  : i(c.begin())
  , e(c.end())
{
}

// Conversion to bool, return true if the iterator
// hasn't yet reached the end of the collection.
template <typename C>
inline const_each<C>::operator bool() const
{
    return i != e;
}

// Preincrement operator.
template <typename C>
inline void const_each<C>::operator++()
{
    ++i;
}

// Iterator comparison.
template <typename C>
inline bool const_each<C>::operator<(const const_iterator& rhs) const
{
    return i < rhs;
}
template <typename C>
inline bool const_each<C>::operator>(const const_iterator& rhs) const
{
    return i > rhs;
}

// Iterator dereference.
template <typename C>
inline const typename const_each<C>::value_type& const_each<C>::operator*() const
{
    return *i;
}
template <typename C>
inline const typename const_each<C>::value_type* const_each<C>::operator->() const
{
    return &(*i);
}


//
// each class implementation.
//

// Constructor.
template <typename C>
inline each<C>::each(C& c)
  : i(c.begin())
  , e(c.end())
{
}

// Conversion to bool, return true if the iterator
// hasn't yet reached the end of the collection.
template <typename C>
inline each<C>::operator bool() const
{
    return i != e;
}

// Preincrement operator.
template <typename C>
inline void each<C>::operator++()
{
    ++i;
}

// Iterator comparison.
template <typename C>
inline bool each<C>::operator<(const iterator& rhs) const
{
    return i < rhs;
}
template <typename C>
inline bool each<C>::operator>(const iterator& rhs) const
{
    return i > rhs;
}

// Iterator dereference.
template <typename C>
inline typename each<C>::value_type& each<C>::operator*()
{
    return *i;
}
template <typename C>
inline typename each<C>::value_type* each<C>::operator->()
{
    return &(*i);
}

}       // namespace foundation

#endif  // !CLASSLIB_STLEXT_H
